/**
* cJSON 工具包
*/

#define _CRT_SECURE_NO_WARNINGS
#include <stdlib.h>
#include <string.h>

#include "utils.h"
#include "cjson_utils2.h"

double cjson_get_field_double(cJSON *json, const char *field, double default_value) {
    if(!json || !field) return default_value;
    json = cJSON_GetObjectItem(json, field);
    if(!json || !cJSON_IsNumber(json)) return default_value;
    return json->valuedouble;
}

const char* cjson_get_field_string(cJSON *json, const char* field) {
    if(!json || !field) return NULL;
    json = cJSON_GetObjectItem(json, field);
    if(!json) return NULL;
    return strdup(json->valuestring); // !!! 注意: 这里 strdup() 会为字符串分配内存 !!!
}

std_err_t cjson_fill_field_string(cJSON *json, const char* field, char *strbuf, size_t bufsize) {
    if(!json || !field || !strbuf || !bufsize) return STD_ERR_INVALID_ARG;
    json = cJSON_GetObjectItem(json, field);
    if(!json) return STD_ERR_NOT_FOUND;
    size_t len = strlen(json->valuestring);
    strncpy(strbuf, json->valuestring, bufsize-1);
    strbuf[bufsize-1] = '\0';
    return len < bufsize ? STD_ERR_OK : STD_ERR_BUFFER_OVERFLOW;
}

#define _cjson_get_num_array(numtype, arr, values, count, terminate_value, converter) \
    if(!arr || (values && (!count || !(*count)))) return NULL;                        \
    size_t cnt = cJSON_GetArraySize(arr); if(!cnt) return NULL;                       \
    if(values) {                                                                      \
        if(*count < cnt) cnt = *count;                                                \
    } else {                                                                          \
        values = (numtype*)malloc0(sizeof(numtype) * (cnt + 1));                      \
        if(!values) return NULL;                                                      \
        values[cnt] = terminate_value;                                                \
    }                                                                                 \
    for(int i=0; i < cnt; i++) {                                                      \
        cJSON *item = cJSON_GetArrayItem(arr, i);                                     \
        if(!item || item->type != cJSON_Number) { cnt = i; break; }                   \
        values[i] = converter(item->valuedouble);                                     \
    }                                                                                 \
    if(count) *count = cnt;                                                           \
    return values;

static inline double  double2double(double val) { return val; }
static inline float   double2float (double val) { return (float)val; }
static inline int64_t double2int64 (double val) { return (int64_t)(val > 0 ? (val + 0.5) : (val - 0.5)); } // 浮点数转整数需要4舍5入
static inline int32_t double2int32 (double val) { return (int32_t)(val > 0 ? (val + 0.5) : (val - 0.5)); } // 浮点数转整数需要4舍5入
static inline int16_t double2int16 (double val) { return (int16_t)(val > 0 ? (val + 0.5) : (val - 0.5)); } // 浮点数转整数需要4舍5入
static inline int8_t  double2int8  (double val) { return (int8_t )(val > 0 ? (val + 0.5) : (val - 0.5)); } // 浮点数转整数需要4舍5入

double * cjson_get_double_array(cJSON *arr, double  *values, size_t *count, double  terminate_value) { _cjson_get_num_array(double , arr, values, count, terminate_value, double2double); }
float  * cjson_get_float_array (cJSON *arr, float   *values, size_t *count, float   terminate_value) { _cjson_get_num_array(float  , arr, values, count, terminate_value, double2float ); }
int64_t* cjson_get_int64_array (cJSON *arr, int64_t *values, size_t *count, int64_t terminate_value) { _cjson_get_num_array(int64_t, arr, values, count, terminate_value, double2int64 ); }
int32_t* cjson_get_int32_array (cJSON *arr, int32_t *values, size_t *count, int32_t terminate_value) { _cjson_get_num_array(int32_t, arr, values, count, terminate_value, double2int32 ); }
int16_t* cjson_get_int16_array (cJSON *arr, int16_t *values, size_t *count, int16_t terminate_value) { _cjson_get_num_array(int16_t, arr, values, count, terminate_value, double2int16 ); }
int8_t * cjson_get_int8_array  (cJSON *arr, int8_t  *values, size_t *count, int8_t  terminate_value) { _cjson_get_num_array(int8_t , arr, values, count, terminate_value, double2int8  ); }

const char** cjson_get_string_array(cJSON *arr, size_t *count) {
    if(count) *count = 0;
    if(!arr) return NULL;

    size_t cnt = cJSON_GetArraySize(arr);
    if(!cnt) return NULL;
    const char **strarr = (const char**)malloc0(sizeof(void*) * (cnt + 1));

    for(int i=0; i < cnt; i++) {
        cJSON *item = cJSON_GetArrayItem(arr, i);
        if(!item || !strlen(item->valuestring)) { cnt = i; break; } // 遇到空字符串就表示结束
        strarr[i] = strdup(item->valuestring); // !!! 注意: 这里 strdup() 会为字符串分配内存 !!!
    }

    // 最后一个字符串为 NULL
    strarr[cnt] = NULL;
    if(count) *count = cnt;
    return strarr;
}
